Skip to content

feat: automatic HTTP/gRPC request metrics#4

Merged
datariot merged 1 commit into
mainfrom
feat/prometheus-auto-metrics
Jul 7, 2026
Merged

feat: automatic HTTP/gRPC request metrics#4
datariot merged 1 commit into
mainfrom
feat/prometheus-auto-metrics

Conversation

@datariot

@datariot datariot commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Closes the review's "automatic metrics aren't automatic" gap (M4). Adding the prometheus bundle now records request metrics with zero per-handler code.

New framework seam

Bundles receive *App in Initialize (which runs before servers are built) but previously had no way to add interceptors or middleware post-construction. Added:

  • AddUnaryInterceptor / AddStreamInterceptor — append to the gRPC interceptor chains
  • AddHTTPMiddleware(func(http.Handler) http.Handler) — ordered middleware applied around the HTTP mux (health, metrics, pprof, and user routes)

All three are no-ops if called after the relevant server is built, and append under the app lock.

Prometheus wiring

Initialize registers a gRPC unary+stream interceptor (status label from status.Code(err).String()) when EnableGRPCMetrics, and an HTTP middleware when EnableHTTPMetrics. Manual RecordHTTPRequest/RecordGRPCRequest still work — purely additive.

Cardinality: the HTTP endpoint label uses r.Pattern (Go 1.22+ matched route template, e.g. GET /users/{id}), falling back to the raw path only for unmatched 404s.

Tests

New framework seam tests (real gRPC call + real HTTP request through seam-added interceptor/middleware; no-op-after-build) and prometheus wiring tests (end-to-end counter increments via prometheus testutil, status derivation, pattern-vs-path labeling).

Full -race suite green, lint 0 issues.

Note: a follow-up docs pass will document this new API and the now-true automatic-metrics claims.

🤖 Generated with Claude Code

…dleware seam

The prometheus bundle exposed RecordHTTPRequest/RecordGRPCRequest but nothing
called them outside the example, so "automatic metrics" weren't automatic.

Add a bundle-time extension seam on framework.App — AddUnaryInterceptor,
AddStreamInterceptor, and AddHTTPMiddleware — that bundles can call from
Initialize (which always runs before the gRPC/HTTP servers are built), with
safe no-ops if called after server construction. AddHTTPMiddleware wraps the
full handler built by startHTTPServer (health, metrics, pprof, and user
HTTPRegistrar routes).

Wire the prometheus bundle's Initialize to register a gRPC interceptor pair
(status derived from google.golang.org/grpc/status) and an HTTP middleware
that records duration/status against RecordGRPCRequest/RecordHTTPRequest for
every call, with no per-handler code required. The HTTP endpoint label
prefers the low-cardinality r.Pattern (Go 1.22+ ServeMux route template),
falling back to the raw path only for unmatched requests. Manual
RecordHTTPRequest/RecordGRPCRequest calls remain fully supported.
@datariot datariot merged commit a55ec54 into main Jul 7, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant